const Binding = uni.requireNativePlugin('bindingx')
const animation = uni.requireNativePlugin('animation')
const dom = uni.requireNativePlugin('dom')
export default {
	data () {
		return {
			disableTouch: false,
			isTouch: false,
			touchTime: 0,
			interval: false,
			loadingType: '',
			direction: ''
		}
	},
	beforeDestroy () {
		if ( this.flipBinding ) {
			Binding.unbind({
				token: this.flipBinding.token,
				eventType: 'pan'
			})
			this.sliderBinding = null
		}
		this.resetFlipAnimationBinding()
	},
	methods: {
		fliptouchstart (event) {
			if ( this.isTouch || this.disableTouch ) {
				return
			}
			this.isTouch = true
			this.touchTime = 0
			this.interval = true
			this.setInterval()
			let touch = event.touches[0]
			this.startX = touch.pageX
			this.startY = touch.pageY
		},
		fliptouchmove (event) {
			if ( this.isTouch && !this.disableTouch ) {
				let touch = event.touches[0]
				let offset = this.vertical ? touch.pageY - this.startY : touch.pageX - this.startX
				if ( !this.direction ) {
					if ( Math.abs(offset) < this.sliderFault ) return
					if ( offset < 0 ) {
						if ( this.nextIndex < this.count && this.nextIndex != 0 ) {
							if ( this.type != 'none' ) {this.direction = 'next'}
						} else if ( this.pullupable && this.loadingState != 'loading' && this.loadingState != 'success' && this.loadingState != 'fail' ) {
							this.loadingType = 'pullup'
							this.disableTouch = true
							this.clearInterval()
							this.pulling()
						}
					} else {
						if ( this.prevIndex > -1 && this.prevIndex != this.count - 1 ) {
							if ( this.type != 'none' ) {this.direction = 'prev'}
						} else if ( this.pulldownable && this.loadingState != 'loading' && this.loadingState != 'success' && this.loadingState != 'fail' ) {
							this.loadingType = 'pulldown'
							this.disableTouch = true
							this.clearInterval()
							this.pulling()
						}
					}
				}
				if ( this.direction ) {
					this.disableTouch = true
					this.flipTouchAction()
				} else {
					this.resetPageBinding()
				}
			}
		},
		async fliptouchend (e) {
			if ( this.isTouch && !this.disableTouch ) {
				let rect = await this.getRect(this.$refs.yingbingFlip)
				let size = this.vertical ? rect.height : rect.width
				this.clearInterval()
				let start = this.vertical ? this.startY : this.startX
				if ( this.touchTime <= 200 && (!this.unableClickPage || this.type == 'none') ) {
					if (start > (size / 4) * 3 && this.nextIndex < this.count && this.nextIndex != 0 ) {
						this.flipToNextBindingX()
					} else if (start < (size / 4) && this.prevIndex >= 0 && this.prevIndex != this.count - 1 ) {
						this.flipToPrevBindingX()
					} else {
						this.resetPageBinding()
					}
				} else {
					this.resetPageBinding()
				}
			}
		},
		async flipTouchAction () {
			let props = []
			let rect = await this.getRect(this.$refs.yingbingFlip)
			let size = this.vertical ? rect.height : rect.width
			let translate = this.translate
			let shadowProperty = this.vertical ? 'height' : 'width'
			let key = this.vertical ? 'y' : 'x'
			if ( this.direction == 'prev' ) {
				if ( this.prevIndex > -1 ) {
					props.push({
						element: this.getEl('yingbingFlipItem_' + this.prevIndex),
						property: 'transform.' + translate,
						expression: `${key} < 0 ? ${-size} : (${key} > ${size} ? 0 : ${key}-${size})`
					})
					if ( this.type == 'real' ) {
						props.push({
							element: this.getEl('yingbingFlipItemContent_' + this.prevIndex),
							property: 'transform.' + translate,
							expression: `${key} < 0 ? ${size} : (${key} > ${size} ? 0 : ${size}-${key})`
						})
						props.push({
							element: this.getEl('yingbingFlipItemBg_' + this.prevIndex),
							property: 'transform.' + translate,
							expression: `${key} < 0 ? 0 : (${key} > ${size} ? ${size} : ${key} + 0)`
						})
						props.push({
							element: this.getEl('yingbingFlipItemShadow_' + this.prevIndex),
							property: shadowProperty,
							expression: `${size} / 2 - abs(${key}) / 2'`
						})
					}
				}
			} else {
				if ( this.nextIndex < this.count ) {
					props.push({
						element: this.getEl('yingbingFlipItem_' + this.nextIndex),
						property: 'transform.' + translate,
						expression: '0+0'
					})
				}
				props.push({
					element: this.getEl('yingbingFlipItem_' + this.currentIndex),
					property: 'transform.' + translate,
					expression: `${key} > 0 ? 0 : (${key} < ${-size} ? ${-size} : ${key} + 0)`
				})
				if ( this.type == 'real' ) {
					props.push({
						element: this.getEl('yingbingFlipItemContent_' + this.currentIndex),
						property: 'transform.' + translate,
						expression: `${key} > 0 ? 0 : (${key} < ${-size} ? ${size} : 0 - ${key})'`
					})
					props.push({
						element: this.getEl('yingbingFlipItemBg_' + this.currentIndex),
						property: 'transform.' + translate,
						expression: `${key} > 0 ? ${size} : (${key} < ${-size} ? 0 : ${key}+${size})`
					})
					props.push({
						element: this.getEl('yingbingFlipItemShadow_' + this.currentIndex),
						property: shadowProperty,
						expression: `abs(${key})/2+0`
					})
				}
			}
			this.flipBinding = Binding.bind({
				anchor: this.getEl('yingbingFlip'),
				eventType: 'pan',
				props: props
			}, (e) => {
				if ((e.state == 'end' || e.state == 'cancel') && this.flipBinding) {
					this.clearInterval()
					Binding.unbind({
						token: this.flipBinding.token,
						eventType: 'pan'
					})
					this.flipBinding = null
					let value = this.direction == 'next' ? 1 : -1;
					if (this.touchTime <= 200) {
						this.pageAnimation(-value * size, size);
					} else {
						let index = this.direction == 'next' ? this.currentIndex : this.prevIndex
						let deltaX = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + index))[translate]
						let offset = this.direction == 'next' ? Math.abs(deltaX) : size - Math.abs(deltaX)
						if ( offset >= size / 4) {
							this.pageAnimation(-value * size, size)
						} else {
							this.pageAnimation(0, size);
						}
					}
				}
			})
		},
		flipToNextBindingX () {
			if ( !this.disableTouch && this.nextIndex < this.count && (this.nextIndex != 0 || this.circular) ) {
				this.direction = 'next'
				this.flipToBindingX()
			}
		},
		flipToPrevBindingX () {
			if ( !this.disableTouch && this.prevIndex >= 0 && (this.prevIndex != this.count - 1 || this.circular) ) {
				this.direction = 'prev'
				this.flipToBindingX()
			}
		},
		async flipToBindingX () {
			this.disableTouch = true
			let value = this.direction == 'next' ? 1 : -1;
			let rect = await this.getRect(this.$refs.yingbingFlip)
			let size = this.vertical ? rect.height : rect.width
			this.pageAnimation(-value * size, size)
		},
		getRect (el) {
			return new Promise(resolve => {
				dom.getComponentRect(el, res => {
					resolve(res.size)
				})
			})
		},
		setInterval () {
			this.touchTimer = setTimeout(() => {
				this.touchTime += 10
				if ( this.interval ) {
					this.setInterval()
				}
			}, 10)
		},
		clearInterval () {
			this.interval = false
			if ( this.touchTimer ) {
				clearTimeout(this.touchTimer)
				this.touchTimer = null
			}
		},
		pageAnimation (offset, size) {
			let duration = this.type == 'none' ? 0.1 : this.duration
			let late = offset
			let translate = this.translate
			let shadowProperty = this.vertical ? 'height' : 'width'
			let props = []
			if ( this.direction == 'prev' ) {
				if ( this.prevIndex > -1 ) {
					let itemTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + this.prevIndex))[translate]
					props.push({
						element: this.getEl('yingbingFlipItem_' + this.prevIndex),
						property: 'transform.' + translate,
						expression: `linear(t, ${itemTrans}, ${late - size - itemTrans}, ${duration})`
					})
					if ( this.type == 'real' ) {
						let contentTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemContent_' + this.prevIndex))[translate]
						props.push({
							element: this.getEl('yingbingFlipItemContent_' + this.prevIndex),
							property: 'transform.' + translate,
							expression: `linear(t, ${contentTrans}, ${-(late - size) - contentTrans}, ${duration})`
						})
						let bgTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemBg_' + this.prevIndex))[translate]
						props.push({
							element: this.getEl('yingbingFlipItemBg_' + this.prevIndex),
							property: 'transform.' + translate,
							expression: `linear(t, ${bgTrans}, ${late - bgTrans}, ${duration})`
						})
						let shadowSize = Binding.getComputedStyle(this.getEl('yingbingFlipItemShadow_' + this.prevIndex))[shadowProperty] || size
						props.push({
							element: this.getEl('yingbingFlipItemShadow_' + this.prevIndex),
							property: shadowProperty,
							expression: `linear(t, ${shadowSize}, ${-(late - size) - shadowSize}, ${duration})`
						})
					}
					this.flipAnimationBinding = Binding.bind({
						eventType: 'timing',
						exitExpression: 't>' + duration,
						props: props
					}, (e) => {
						if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) {
							Binding.unbind({
								token: this.flipAnimationBinding.token,
								eventType: 'timing'
							})
							this.flipAnimationBinding = null
							if ( Math.abs(offset) > 0 ) {
								this.handleFlipChange(this.direction == 'next' ? 1 : -1)
								this.$nextTick(function () {
									this.resetPageBinding()
								})
							} else {
								this.resetPageBinding();
							}
						}
					})
				}
			} else {
				if ( this.nextIndex < this.count ) {
					animation.transition(this.getRef('yingbingFlipItem_' + this.nextIndex), {
						styles: {
							transform: `${translate}(0)`
						},
						duration: 0,
						timingFunction: 'linear',
						needLayout: true
					})
				}
				animation.transition(this.getRef('yingbingFlipItem_' + this.currentIndex), {
					styles: {
						transform: `${translate}(${late}px)`
					},
					duration: duration,
					timingFunction: 'linear',
					needLayout: true
				}, () => {
					if ( Math.abs(offset) > 0 ) {
						this.handleFlipChange(this.direction == 'next' ? 1 : -1)
						this.$nextTick(function () {
							this.resetPageBinding()
						})
					} else {
						this.resetPageBinding();
					}
				})
				if ( this.type == 'real' ) {
					animation.transition(this.getRef('yingbingFlipItemContent_' + this.currentIndex), {
						styles: {
							transform: `${translate}(${-late}px)`
						},
						duration: duration,
						timingFunction: 'linear',
						needLayout: true
					})
					animation.transition(this.getRef('yingbingFlipItemBg_' + this.currentIndex), {
						styles: {
							transform: `${translate}(${size + late}px)`
						},
						duration: duration,
						timingFunction: 'linear',
						needLayout: true
					})
					let styles = {}
					styles[shadowProperty] = -late + 'px'
					animation.transition(this.getRef('yingbingFlipItemShadow_' + this.currentIndex), {
						styles: styles,
						duration: duration,
						timingFunction: 'linear',
						needLayout: true
					})
				}
				// if ( this.nextIndex < this.count ) {
					// props.push({
					// 	element: this.getEl('yingbingFlipItem_' + this.nextIndex),
					// 	property: 'transform.' + translate,
					// 	expression: '0+0'
					// })
				// }
				// let itemTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItem_' + this.currentIndex))[translate]
				// props.push({
				// 	element: this.getEl('yingbingFlipItem_' + this.currentIndex),
				// 	property: 'transform.' + translate,
				// 	expression: `linear(t, ${itemTrans}, ${late - itemTrans}, ${duration})`
				// })
				// if ( this.type == 'real' ) {
					// let contentTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemContent_' + this.currentIndex))[translate]
					// props.push({
					// 	element: this.getEl('yingbingFlipItemContent_' + this.currentIndex),
					// 	property: 'transform.' + translate,
					// 	expression: `linear(t, ${contentTrans}, ${-late - contentTrans}, ${duration})`
					// })
					// let bgTrans = Binding.getComputedStyle(this.getEl('yingbingFlipItemBg_' + this.currentIndex))[translate]
					// props.push({
					// 	element: this.getEl('yingbingFlipItemBg_' + this.currentIndex),
					// 	property: 'transform.' + translate,
					// 	expression: `linear(t, ${bgTrans}, ${size + late - bgTrans}, ${duration})`
					// })
					// let shadowSize = Binding.getComputedStyle(this.getEl('yingbingFlipItemShadow_' + this.currentIndex))[shadowProperty]
					// props.push({
					// 	element: this.getEl('yingbingFlipItemShadow_' + this.currentIndex),
					// 	property: shadowProperty,
					// 	expression: `linear(t, ${shadowSize}, ${-late - shadowSize}, ${duration})`
					// })
				// }
			}
		},
		pulling () {
			let loadingType = this.loadingType
			let size = loadingType == 'pullup' ? this.pullupHeight : this.pulldownHeight
			let key = this.vertical ? 'y' : 'x'
			let translate = this.translate
			let props = [
				{
					element: this.getEl('yingbing_flip_' + loadingType),
					property: 'transform.' + translate,
					expression: loadingType == 'pullup' ? `abs(${key}) > ${size} ? 0 : ${key} + ${size}` : `abs(${key}) > ${size} ? 0 : ${key} - ${size}`
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_default'),
					property: 'opacity',
					expression: `abs(${key}) < ${size} ? 1 : 0`
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_ready'),
					property: 'opacity',
					expression: `abs(${key}) < ${size} ? 0 : 1`
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_loading'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_success'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_fail'),
					property: 'opacity',
					expression: '0+0'
				}
			]
			this.flipBinding = Binding.bind({
				anchor: this.getEl('yingbingFlip'),
				eventType: 'pan',
				props: props
			}, (e) => {
				if ((e.state == 'end' || e.state == 'cancel') && this.flipBinding) {
					Binding.unbind({
						token: this.flipBinding.token,
						eventType: 'pan'
					})
					this.flipBinding = null
					let deltaX = Binding.getComputedStyle(this.getEl('yingbing_flip_' + loadingType))[translate]
					if ( deltaX == 0 ) {
						this.loadingState = 'ready'
						this.pullingRefreshBindingx()
					} else {
						this.loadingState = 'default'
						this.resetPullingBindingx()
					}
				}
			})
		},
		resetPullingBindingx () {
			let loadingType = this.loadingType
			let translate = this.translate
			let size = loadingType == 'pullup' ? this.pullupHeight : this.pulldownHeight
			let trans = loadingType == 'pullup' ? size : -size
			let deltaX = Binding.getComputedStyle(this.getEl('yingbing_flip_' + loadingType))[translate]
			let duration = 300
			let props = [
				{
					element: this.getEl('yingbing_flip_' + loadingType),
					property: 'transform.' + translate,
					expression: `linear(t, ${deltaX}, ${trans}, ${duration})`
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_default'),
					property: 'opacity',
					expression: this.loadingState == 'default' ? '1+0' : '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_ready'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_loading'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_success'),
					property: 'opacity',
					expression: this.loadingState == 'success' ? '1+0' : '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_fail'),
					property: 'opacity',
					expression: this.loadingState == 'fail' ? '1+0' : '0+0'
				}
			]
			this.flipAnimationBinding = Binding.bind({
				eventType: 'timing',
				exitExpression: 't>' + duration,
				props: props
			}, (e) => {
				if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) {
					this.resetFlipAnimationBinding()
					this.loadingState = ''
					this.resetPageBinding()
				}
			})
		},
		pullingRefreshBindingx () {
			let loadingType = this.loadingType
			let duration = 1
			let props = [
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_default'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_ready'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_loading'),
					property: 'opacity',
					expression: '1+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_success'),
					property: 'opacity',
					expression: '0+0'
				},
				{
					element: this.getEl('yingbing_flip_' + loadingType + '_fail'),
					property: 'opacity',
					expression: '0+0'
				}
			]
			this.flipAnimationBinding = Binding.bind({
				eventType: 'timing',
				exitExpression: 't>' + duration,
				props: props
			}, (e) => {
				if (e.state == 'exit' && this.flipAnimationBinding && e.t > duration) {
					this.resetFlipAnimationBinding()
					this.pullingRefresh(loadingType)
				}
			})
		},
		resetFlipAnimationBinding () {
			if ( this.flipAnimationBinding ) {
				Binding.unbind({
					token: this.flipAnimationBinding.token,
					eventType: 'timing'
				})
				this.flipAnimationBinding = null
			}
		},
		getEl (selector) {
			const el = this.$refs[selector] && this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector]
			if ( !el ) return null
			if (typeof el === 'string' || typeof el === 'number') return el;
			if (WXEnvironment) {
			    return el.ref;
			} else {
			    return el instanceof HTMLElement ? el : el.$el;
			}
		},
		getRef (selector) {
			return this.$refs[selector] ? this.$refs[selector].length > 0 ? this.$refs[selector][0] : this.$refs[selector] : null
		},
		resetPageBinding () {
			this.direction = ''
			this.touchTime = 0
			this.startX = 0
			this.startY = 0
			this.$nextTick(function () {
				this.isTouch = false
				this.disableTouch = false
			})
		}
	}
}